
//字节面试题并发控制：
/**
 * 请实现如下函数，可以批量请求数据。所有的url地址都在urls参数中，
 * 同时可以通过limit控制请求的并发度，当所有请求结束后，调用callback回调函数。请求直接用fetch就可以。
 * 参考：https://zhuanlan.zhihu.com/p/123279828
 */


var urls = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20];
const limit = 5;

// 主函数
function sendRequest(urls, limit , callback) {
    function send(urls){
        const url = urls.shift();
        if(url){
            return new Promise((resolve,reject)=>{
                setTimeout(()=>{
                    console.log('发送的请求是：',url);
                    resolve(url);
                },10)
            }).finally(()=>{
                if(urls.length){ return send(urls)}
            })
        }
    };
    let asyncLists = [];
    while(limit--){
        asyncLists.push(send(urls));
    }
    console.log(asyncLists,'list')
    return Promise.all(asyncLists).then(callback);
}

sendRequest(urls,5,function(){
    console.log('done')
});

//中止fetch
const controller = new AbortController();
const {signal} = controller;

fetch('localhost:8080',{signal}).then(res=>{
    console.log('completed')
}).catch(e=>{
    if(e.name === 'AbortError'){
        console.log('i have been canceled')
    }
})

//异步求和函数： 提供一个异步 add 方法如下，需要实现一个 await sum(...args) 函数：
function asyncAdd(a, b, callback) { //提供的方法
    setTimeout(function () {
      callback(null, a + b);
    }, 1000);
}

async function sum(...args) {
    if (args.length > 1) {
      const result = await new Promise((resolve) => {
        asyncAdd(args[0], args[1], (err, result) => {
          if (!err) {
            resolve(result);
          }
        });
      });
      return sum(result, ...args.splice(2));
    }
    return args[0];
}

//执行：
const res = async()=>{
    console.time('sum')
    const res1 = await sum(1,2,3,4,5); console.log(res1);
    console.timeEnd('sum')
};
res(); //sum: 4017.469ms


//优化版版本： sum: 3016.062ms
function createAdd(a, b = 0) {
    return new Promise((resolve) => {
      asyncAdd(a, b, (err, result) => {
        if (!err) {
          resolve(result);
        }
      });
    });
  }

async function sum(...args) {
    if (args.length > 1) {
      const result = [];
      for (let i = 0; i < args.length; i = i + 2) {
        result.push(createAdd(args[i], args[i + 1]));
      }
      return sum(...(await Promise.all(result)));
    }
    return args[0];
}
/**
 * 实现一个带并发限制的promise异步调度器-字节
 * JS实现一个带并发限制的异步调度器Scheduler,保证同时运行的任务最多有两个。完善下面代码中的Scheduler类，使得以下程序能正确输出。
 */

 class Scheduler {
    constructor(){
        this.lists = [];
        this.limit = 2;
        this.tempRunIndex = 0;
    }
    add(promiseCreator){
        this.lists.push(promiseCreator)
    }
    taskStart(){
        for(let i=0;i<this.limit;i++){
            this.request();
        }
    }
    request(){
        if(!this.lists || !this.lists.length || this.tempRunIndex >= this.limit){
            return;
        }
        this.tempRunIndex ++;
        this.lists.shift()().then(()=>{
            this.tempRunIndex --;
            this.request();
        })
    }
}
const timeout = (time)=> new Promise(resolve=>{
    setTimeout(resolve,time);
});
const scheduler = new Scheduler();
const addTask = (time,order) =>{
    scheduler.add(()=>timeout(time).then(()=>console.log(order)));
}

addTask(1000,'1');
addTask(500,'2');
addTask(300,'3');
addTask(400,'4');
scheduler.taskStart();



1.async function async1() {
    console.log('async1 start');
    await async2()
    console.log('async1 end');
  }

  async function async2() { console.log('async2') }

  console.log('script start');

  setTimeout(function() {
  console.log('setTimeout');
  }, 0)

  async1();

  new Promise(function(resolve) {
    console.log('promise1');
    resolve();
  }).then(function() {
    console.log('promise2');
  });

  console.log('script end');



// 写一个 mySetInterVal(fn, a, b),
// 每次间隔 a,a+b,a+2b,...,a+nb 的时间，
// 然后写一个 myClear，
// 停止上面的 mySetInterVal
const mySetInterVal = (fn, a, b, n)=>{
    let index = 0;
    const run = (fn)=>{
        let time = (a + index * b) * 1000;
        index++;
        if(index<=n){
            console.log(time,'time')
            return new Promise((resolve,reject)=>{
                setTimeout(()=>{
                    fn();
                    resolve();
                },time);
            }).finally(()=>{
                return run(fn);
            })
        }
    }
    let lists = [];
    lists.push(run(fn));
    return Promise.all(lists);
}
const cf = ()=>{
    console.log(111);
}
mySetInterVal(cf,1,2,3);
